package com.example.cloud.service.basic.info.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.cloud.constants.CommonConstants;
import com.example.cloud.constants.StateConstants;
import com.example.cloud.dao.basic.info.MemberDiscountProductCategoryRepository;
import com.example.cloud.dao.basic.info.MemberDiscountProductRepository;
import com.example.cloud.dao.basic.info.MemberDiscountProjectRepository;
import com.example.cloud.dao.basic.info.MemberDiscountProjectTypeRepository;
import com.example.cloud.dao.basic.info.MemberDiscountRepository;
import com.example.cloud.dao.basic.info.MemberRepository;
import com.example.cloud.dao.business.medical.*;
import com.example.cloud.dao.business.reservation.PatientRepository;
import com.example.cloud.dao.finance.*;
import com.example.cloud.dao.inventory.InventoryDetailsRepository;
import com.example.cloud.dao.inventory.InventoryRepository;
import com.example.cloud.dao.mongdb.basic.info.MongoMemberLevelRepository;
import com.example.cloud.dao.mongdb.system.MongoUserRepository;
import com.example.cloud.dao.statistics.StatisticsFinancialRepository;
import com.example.cloud.model.basic.MemberLevel;
import com.example.cloud.model.basic.ServiceProject;
import com.example.cloud.model.business.medical.*;
import com.example.cloud.model.business.reservation.Patient;
import com.example.cloud.model.business.reservation.VisitRecord;
import com.example.cloud.model.dto.PayInfo;
import com.example.cloud.model.dto.Result;
import com.example.cloud.model.finance.*;
import com.example.cloud.model.inventory.Inventory;
import com.example.cloud.model.inventory.InventoryDetails;
import com.example.cloud.model.member.Member;
import com.example.cloud.model.member.MemberDiscount;
import com.example.cloud.model.member.MemberDiscountProduct;
import com.example.cloud.model.member.MemberDiscountProductCategory;
import com.example.cloud.model.member.MemberDiscountProject;
import com.example.cloud.model.member.MemberDiscountProjectType;
import com.example.cloud.model.statistics.StatisticsFinancial;
import com.example.cloud.model.system.SystemConfig;
import com.example.cloud.model.system.User;
import com.example.cloud.service.basic.info.MemberLevelService;
import com.example.cloud.service.basic.info.MemberService;
import com.example.cloud.service.system.SystemConfigService;
import com.example.cloud.utils.BusinessUtil;
import com.example.cloud.utils.DateUtils;
import com.example.cloud.utils.RequestUtil;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by wangtao on 2018/6/6.
 */
@Service
public class MemberServiceImpl implements MemberService {

    private static final Logger logger = Logger.getLogger(MemberServiceImpl.class);

    @PersistenceContext
    EntityManager em;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    private MemberRepository memberRepository;

    @Autowired
    private MemberLevelService memberLevelService;

    @Autowired
    private MongoMemberLevelRepository mongoMemberLevelRepository;

    @Autowired
    private MemberDiscountRepository memberDiscountRepository;

    @Autowired
    private RechargeRecordRepository rechargeRecordRepository;

    @Autowired
    private GiftRecordRepository giftRecordRepository;

    @Autowired
    private ConsumeRecordRepository consumeRecordRepository;

    @Autowired
    private ConsumeDetailsRecordRepository consumeDetailsRecordRepository;

    @Autowired
    private ConsumeDiscountRepository consumeDiscountRepository;

    @Autowired
    private PaymentDetailsRepository paymentDetailsRepository;

    @Autowired
    private AccountChangeDetailsRepository accountChangeDetailsRepository;

    @Autowired
    private PatientRepository patientRepository;

    @Autowired
    private TreatPlanServiceProjectRepository serviceProjectRepository;

    @Autowired
    private ChargeDetailsRepository chargeDetailsRepository;

    @Autowired
    private TreatPlanCourseRepository treatPlanCourseRepository;

    @Autowired
    private TreatPlanCourseDetailsRepository treatPlanCourseDetailsRepository;

    @Autowired
    private TreatPlanCourseProductRepository treatPlanCourseProductRepository;

    @Autowired
    private TreatPlanHomeRepository treatPlanHomeRepository;

    @Autowired
    private TreatPlanHomeProjectRepository treatPlanHomeProjectRepository;

    @Autowired
    private TreatPlanHomeProductRepository treatPlanHomeProductRepository;

    @Autowired
    private DeductRecordRepository deductRecordRepository;

    @Autowired
    private WaitPaymentRepository waitPaymentRepository;

    @Autowired
    private MakeRecordRepository makeRecordRepository;

    @Autowired
    private InventoryRepository inventoryRepository;

    @Autowired
    private InventoryDetailsRepository inventoryDetailsRepository;

    @Autowired
    private AppProductRecordRepository appProductRecordRepository;

    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private TreatPlanHomeDiscountProductRepository discountProductRepository;

    @Autowired
    private TreatPlanHomeDiscountProductDetailsRepository discountProductDetailsRepository;

    @Autowired
    private TreatPlanHomeDiscountProjectRepository discountProjectRepository;

    @Autowired
    private TreatPlanHomeDiscountProjectDetailsRepository discountProjectDetailsRepository;

    @Autowired
    private MemberDiscountProductCategoryRepository memberDiscountProductCategoryRepository;

    @Autowired
    private MemberDiscountProductRepository memberDiscountProductRepository;

    @Autowired
    private MemberDiscountProjectRepository memberDiscountProjectRepository;

    @Autowired
    private MemberDiscountProjectTypeRepository memberDiscountProjectTypeRepository;

    @Autowired
    private MongoUserRepository mongoUserRepository;

    @Autowired
    private StatisticsFinancialRepository statisticsFinancialRepository;

    @Override
    public Member findOne(Long id) {
        return memberRepository.findOne(id);
    }

    @Override
    public Member findByPatientId(Long patientId) {
        return memberRepository.findByPatientIdAndDeleteFlag(patientId, 0);
    }

    @Override
    public Member findByPhone(String phone) {
        return memberRepository.findByPhone(phone);
    }

    @Override
    public List<Member> findMember(String searchValue) {
        User user = RequestUtil.getLoginUser();
        StringBuilder sql = new StringBuilder("select * from member");
        sql.append(" where account_id = :accountId");
        sql.append(" and (patient_name like :patientName");
        sql.append(" or member_number like :memberNumber)");
        sql.append(" and delete_flag = 0");
        Query query = em.createNativeQuery(sql.toString(), Member.class);
        query.setParameter("accountId", user.getAccountId());
        query.setParameter("patientName", "%" + searchValue + "%");
        query.setParameter("memberNumber", "%" + searchValue + "%");
        List<Member> resultList = query.getResultList();
        // 携带患者信息
        for (Member member : resultList) {
            if (member.getPatientId() != null) {
                Patient patient = patientRepository.findOne(member.getPatientId());
                if (patient != null) {
                    member.setPatient(patient);
                }
            }
        }
        return resultList;
    }

    /**
     * 以调用事务为主
     * @param patient
     * @return
     */
    @Override
    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
    public Result openAccount(Patient patient) {
        Result result = new Result();
        result.setCode(CommonConstants.SUCCESS);
        User user = RequestUtil.getLoginUser();
        Member member = new Member();
        member.setPatientId(patient.getId());
        member.setPatientName(patient.getName());
        member.setMemberNumber(patient.getMedicalNumber());
        member.setMemberName(patient.getName());
        // 获取默认会员等级
        MemberLevel memberLevel = memberLevelService.findDefault(user.getAccountId());
        if (memberLevel == null) {
            result.setCode(CommonConstants.FAILURE);
            result.setMsg("请先设置默认会员等级");
            return result;
        }
        member.setLevelId(memberLevel.getId());
        member.setLevelName(memberLevel.getLevelName());
        member.setStar(memberLevel.getLevel() == null ? 0 : memberLevel.getLevel());
        member.setPhone(patient.getPhone());
        member.setScore(1000);
        member.setAccountId(user.getAccountId());
        member.setUserId(user.getId());
        member.setOrganId(user.getOrganId());
        member.setOrganName(user.getOrganName());
        BusinessUtil.appendRecord(member);
        member = memberRepository.save(member);
        // 添加会员折扣
        memberDiscountRepository.save(generateMemberDiscount(member, memberLevel));

        // 更新患者
        StringBuilder sql = new StringBuilder("update basic_patient set is_member = 1 where id = :id");
        Query query = em.createNativeQuery(sql.toString());
        // 变更为会员
        query.setParameter("id", patient.getId());
        query.executeUpdate();
        result.setData(member);
        return result;
    }

    public MemberDiscount generateMemberDiscount(Member member, MemberLevel memberLevel) {
        MemberDiscount discount = new MemberDiscount();
        discount.setPatientId(member.getPatientId());
        discount.setMemberId(member.getId());
        discount.setDiscountName("会员折扣");
        discount.setDiscount(memberLevel.getDiscount());
        BusinessUtil.appendRecord(discount);
        return discount;
    }

    @Override
    @Transactional
    public Result doRecharge(RechargeRecord record) {
        Result result = new Result();
        result.setCode(CommonConstants.SUCCESS);
        Member member = memberRepository.findOne(record.getMemberId());
        if (member != null) {
            // 账户变动信息
            AccountChangeDetails changeDetails = new AccountChangeDetails();
            // 记录充值前账户信息
            beforeAccount(changeDetails, member);
            // 会员储值账户
            BigDecimal storeAccount = member.getStoreAccount();
            // 会员累计金额
            BigDecimal memberAmount = member.getMemberAmount();
            // 累计充值
            BigDecimal totalStoreAmount = member.getTotalStoreAmount();
            // 本次充值
            BigDecimal rechargeAmount = record.getRechargeAmount();
            // 充值到储值账户
            storeAccount = storeAccount.add(rechargeAmount);
            // 累加会员充值金额
            totalStoreAmount = totalStoreAmount.add(rechargeAmount);
            // 是否累计会员金额
            int isGrand = 0;

            // 计算折扣
            if (member.getLevelId() != null) {
                MemberLevel level = memberLevelService.findOne(member.getLevelId());
                if (level != null) {
                    // 指定充值金额
                    BigDecimal storeAmount = level.getStoreAmount();
                    // 本次充值金额大于指定充值金额
                    if (rechargeAmount.compareTo(storeAmount) > 0) {
                        isGrand = 1;
                        memberAmount = memberAmount.add(rechargeAmount);
                        // 会员累计金额大于指定升级金额
                        level = getLevel(level, memberAmount);
                        member.setLevelId(level.getId());
                        member.setLevelName(level.getLevelName());
                        // 更新会员折扣
                        MemberDiscount memberDiscount = memberDiscountRepository.findByMemberIdAndDeleteFlag(member.getId(), 0);
                        if (memberDiscount != null) {
                            memberDiscount.setDiscount(level.getDiscount());
                        } else {
                            memberDiscount = new MemberDiscount();
                            memberDiscount.setPatientId(member.getPatientId());
                            memberDiscount.setMemberId(member.getId());
                            memberDiscount.setDiscountName("会员折扣");
                            memberDiscount.setDiscount(level.getDiscount());
                        }
                        BusinessUtil.appendRecord(memberDiscount);
                        memberDiscountRepository.save(memberDiscount);
                    }
                }
            }

            // 保存充值记录
            record.setIsGrand(isGrand);
            record.setSource(StateConstants.SOURCE_MEDICAL_SYSTEM);
            BusinessUtil.appendRecord(record);
            record = rechargeRecordRepository.save(record);

            // 生成付款明细
            PaymentDetails paymentDetails = record.getPaymentDetails();
            paymentDetails.setRecordId(record.getId());
            paymentDetails.setRecordType(StateConstants.RECORD_TYPE_RECHARGE);
            BusinessUtil.appendRecord(paymentDetails);
            paymentDetailsRepository.save(paymentDetails);

            // 更新会员
            member.setStoreAccount(storeAccount);
            member.setMemberAmount(memberAmount);
            member.setTotalStoreAmount(totalStoreAmount);
            BusinessUtil.appendRecord(member);
            memberRepository.save(member);

            // 记录账户变动后的信息
            afterAccount(changeDetails, member);
            changeDetails.setRecordId(record.getId());
            changeDetails.setRecordType(StateConstants.RECORD_TYPE_RECHARGE);
            // 保存账户变动
            accountChangeDetailsRepository.save(changeDetails);
        }
        // 判断是否打印小票
        int autoPrint = checkPrint();
        Map<String, Object> params = new HashMap();
        if(autoPrint == StateConstants.AUTO_PRINT_YES){
            JSONObject json = new JSONObject();
            json.put("medicalNumber", member.getMemberNumber());
            json.put("memberName", member.getMemberName());
            json.put("afterLevelName", member.getLevelName());
            json.put("afterStoreAccount", member.getStoreAccount());
            json.put("storedAmount", record.getRechargeAmount());
            json.put("bankCard", record.getPaymentDetails().getBankCard());
            json.put("alipay", record.getPaymentDetails().getAlipay());
            json.put("wechat", record.getPaymentDetails().getWechat());
            json.put("cash", record.getPaymentDetails().getCash());
            json.put("creationTime", DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            json.put("createdBy", RequestUtil.getLoginUser().getUsername());
            params.put("task", json);
        }
        params.put("autoPrint", autoPrint);
        result.setParams(params);
        return result;
    }

    // 充值前账户信息
    public void beforeAccount(AccountChangeDetails changeDetails, Member member) {
        changeDetails.setBeforeStoreAccount(member.getStoreAccount());
        changeDetails.setBeforeGiftAccount(member.getGiftAccount());
        changeDetails.setBeforeCourseAccount(member.getCourseAccount());
        changeDetails.setBeforeMemberAmount(member.getMemberAmount());
        changeDetails.setBeforeLevelName(member.getLevelName());
    }

    // 充值后账户信息
    public void afterAccount(AccountChangeDetails changeDetails, Member member) {
        changeDetails.setAfterStoreAccount(member.getStoreAccount());
        changeDetails.setAfterGiftAccount(member.getGiftAccount());
        changeDetails.setAfterCourseAccount(member.getCourseAccount());
        changeDetails.setAfterMemberAmount(member.getMemberAmount());
        changeDetails.setAfterLevelName(member.getLevelName());
    }

    // 递归取得本次充值后对应的会员等级
    public MemberLevel getLevel(MemberLevel level, BigDecimal memberAmount) {
        if (memberAmount.compareTo(level.getUpAmount()) > 0) {
            if (level.getNextLevelId() != null) {
                level = mongoMemberLevelRepository.findOne(level.getNextLevelId());
                if (level != null) {
                    getLevel(level, memberAmount);
                }
            }
        }
        return level;
    }

    @Override
    @Transactional
    public Result doGift(GiftRecord record) {
        Result result = new Result();
        result.setCode(CommonConstants.SUCCESS);
        Member member = memberRepository.findOne(record.getMemberId());
        if (member != null) {
            // 账户变动信息
            AccountChangeDetails changeDetails = new AccountChangeDetails();
            // 记录充值前账户信息
            beforeAccount(changeDetails, member);
            // 累计赠送金额
            BigDecimal totalGiftAmount = member.getTotalGiftAmount();
            // 会员赠送账户
            BigDecimal giftAccount = member.getGiftAccount();
            // 本次赠送金额
            BigDecimal giftAmount = record.getGiftAmount();
            giftAccount = giftAccount.add(giftAmount);
            totalGiftAmount = totalGiftAmount.add(giftAmount);

            // 保存赠送记录
            BusinessUtil.appendRecord(record);
            giftRecordRepository.save(record);

            // 更新会员信息
            member.setGiftAccount(giftAccount);
            member.setTotalGiftAmount(totalGiftAmount);
            BusinessUtil.appendRecord(member);
            memberRepository.save(member);

            // 记录账户变动后的信息
            afterAccount(changeDetails, member);
            changeDetails.setRecordId(record.getId());
            changeDetails.setRecordType(StateConstants.RECORD_TYPE_GIFT);
            // 保存账户变动
            accountChangeDetailsRepository.save(changeDetails);
        }
        // 判断是否打印小票
        int autoPrint = checkPrint();
        Map<String, Object> params = new HashMap();
        if(autoPrint == StateConstants.AUTO_PRINT_YES){
            JSONObject json = new JSONObject();
            json.put("medicalNumber", member.getMemberNumber());
            json.put("memberName", member.getMemberName());
            json.put("afterLevelName", member.getLevelName());
            json.put("afterGiftAccount", member.getGiftAccount());
            json.put("giftAmount", record.getGiftAmount());
            json.put("remark", record.getGiftRemark());
            json.put("creationTime", DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            json.put("createdBy", RequestUtil.getLoginUser().getUsername());
            params.put("task", json);
        }
        params.put("autoPrint", autoPrint);
        result.setParams(params);
        return result;
    }

    @Override
    @Transactional
    public Result doPayment(List<ChargeDetails> records, List<ConsumeDiscount> discounts, PayInfo payInfo, PaymentDetails paymentDetails, List<Long> ids) {
        Result result = new Result();
        result.setCode(CommonConstants.SUCCESS);
        result.setMsg("付款成功");
        // 校验付款金额
        result = validPayAmount(result, payInfo, paymentDetails);
        if (result.getCode().equals(CommonConstants.FAILURE)) {
            return result;
        }
        Member member = memberRepository.findOne(records.get(0).getMemberId());
        if (member != null) {
            // 账户变动信息
            AccountChangeDetails changeDetails = new AccountChangeDetails();
            // 记录充值前账户信息
            beforeAccount(changeDetails, member);
            // 会员疗程账户
            BigDecimal courseAccount = member.getCourseAccount();
            // 校验会员账户
            result = validMemberAccount(result, member, paymentDetails);
            if (result.getCode().equals(CommonConstants.FAILURE)) {
                return result;
            }

            // 校验库存
            Map<Long, Map<String, Integer>> itemMap = new HashMap<>();
            for (ChargeDetails record : records) {
                int quantity = record.getQuantity();
                if (record.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_PRODUCT) {
                    Long itemId = record.getItemId();
                    if (itemMap.containsKey(itemId)) {
                        String itemName = record.getItemName();
                        Map<String, Integer> map = itemMap.get(itemId);
                        int vl = map.get(itemName).intValue();
                        map.put(itemName, vl + quantity);
                        itemMap.put(itemId, map);
                    } else {
                        Map<String, Integer> map = new HashMap<>();
                        map.put(record.getItemName(), quantity);
                        itemMap.put(itemId, map);
                    }
                }
            }
            result = validInventory(result, itemMap);
            if (result.getCode().equals(CommonConstants.FAILURE)) {
                return result;
            }

            // 扣减库存
            List<Inventory> inventoryList = new ArrayList<>();
            List<InventoryDetails> inventoryDetailsList = new ArrayList<>();
            for (Map.Entry<Long, Map<String, Integer>> entry1 : itemMap.entrySet()) {
                for (Map.Entry<String, Integer> entry2 : entry1.getValue().entrySet()) {
                    // 商品主键
                    Long itemId = entry1.getKey();
                    // 预扣减库存
                    int quantity = entry2.getValue().intValue();
                    // 扣减库存
                    Inventory inventory = inventoryRepository.findByItemId(itemId);
                    inventory.setTotalInventory(inventory.getTotalInventory() - quantity);
                    inventory.setUseInventory(inventory.getUseInventory() - quantity);
                    BusinessUtil.appendRecord(inventory);
                    inventoryList.add(inventory);
                    // 扣减库存明细
                    List<InventoryDetails> inventoryDetails = inventoryDetailsRepository.findByInventoryIdAndUseInventoryGreaterThan(inventory.getId(), 0);
                    for (InventoryDetails inventoryDetail : inventoryDetails) {
                        // 明细总库存
                        int totalInventory = inventoryDetail.getTotalInventory();
                        // 明细可用库存
                        int useInventory = inventoryDetail.getUseInventory();
                        if (quantity < useInventory) {
                            // 预扣减库存小于可用库存
                            totalInventory -= quantity;
                            useInventory -= quantity;
                            quantity = 0;
                        } else if (quantity == useInventory) {
                            // 预扣减库存等于可用库存
                            totalInventory -= quantity;
                            useInventory = 0;
                            quantity = 0;
                        } else if (quantity > useInventory) {
                            // 预扣减库存大于可用库存
                            totalInventory -= useInventory;
                            useInventory = 0;
                            quantity -= useInventory;
                        }
                        inventoryDetail.setTotalInventory(totalInventory);
                        inventoryDetail.setUseInventory(useInventory);
                        BusinessUtil.appendRecord(inventoryDetail);
                        inventoryDetailsList.add(inventoryDetail);

                        // TODO 生成出库记录
                        if (quantity == 0) {
                            break;
                        }
                    }
                }
            }
            // 更新库存
            if (!inventoryList.isEmpty()) {
                inventoryRepository.save(inventoryList);
            }
            // 更新库存明细
            if (!inventoryDetailsList.isEmpty()) {
                inventoryDetailsRepository.save(inventoryDetailsList);
            }

            // 生成消费记录
            ConsumeRecord consumeRecord = new ConsumeRecord();
            consumeRecord.setPatientId(member.getPatientId());
            consumeRecord.setMemberId(member.getId());
            consumeRecord.setMemberName(member.getPatientName());
            consumeRecord.setMemberNumber(member.getMemberNumber());
            consumeRecord.setPaymentType(StateConstants.CONSUME_RECORD_PAYMENT_TYPE_PAY);
            consumeRecord.setPayAmount(payInfo.getPayAmount());
            consumeRecord.setDiscountAmount(payInfo.getDiscountAmount());
            consumeRecord.setDeductAmount(payInfo.getDeductAmount());
            consumeRecord.setActualAmount(payInfo.getActualAmount());
            BusinessUtil.appendRecord(consumeRecord);
            consumeRecord = consumeRecordRepository.save(consumeRecord);

            // 保存使用的折扣
            for (ConsumeDiscount discount : discounts) {
                discount.setRecordId(consumeRecord.getId());
            }
            if (!discounts.isEmpty()) {
                consumeDiscountRepository.save(discounts);
            }

            // 更新付费状态
            // 单次项目
            List<Long> projectIds = new ArrayList<>();
            // 单次产品
            List<Long> productIds = new ArrayList<>();
            // 服务费
            List<Long> serviceIds = new ArrayList<>();
            // 外科项目
            List<Long> surgicalIds = new ArrayList<>();
            // 长期疗程
            List<Long> courseIds = new ArrayList<>();
            // 长期疗程产品
            List<Long> courseProductIds = new ArrayList<>();
            // 家庭病房
            List<Long> homeIds = new ArrayList<>();
            // 待付款明细
            List<Long> chargeIds = new ArrayList<>();
            for (ChargeDetails chargeDetails : records) {
                chargeIds.add(chargeDetails.getId());
                Long businessId = chargeDetails.getBusinessId();
                // 单次收费
                if (chargeDetails.getBusinessType() == StateConstants.CHARGE_BUSINESS_TYPE_ONE) {
                    if (chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_PROJECT) {
                        // 项目
                        projectIds.add(businessId);
                    } else if (chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_PRODUCT) {
                        // 产品
                        productIds.add(businessId);
                    } else if (chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_SERVICE_PROJECT) {
                        // 服务项目
                        serviceIds.add(businessId);
                    }
                    // 长期收费
                } else if (chargeDetails.getBusinessType() == StateConstants.CHARGE_BUSINESS_TYPE_COURSE) {
                    if (chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_COURSE) {
                        // 疗程
                        courseIds.add(businessId);
                        // 判断是否需要生成待交费明细
                        WaitPayment waitPayment = generateWaitPayment(member, chargeDetails, StateConstants.WAIT_PAYMENT_TREAT_TYPE_COURSE);
                        if (waitPayment != null) {
                            waitPaymentRepository.save(waitPayment);
                        }
                        // 实付金额同步到疗程中
                        StringBuilder sql = new StringBuilder("update treat_plan_course set actual_amount = :actualAmount where id = :id");
                        Query query = em.createNativeQuery(sql.toString());
                        query.setParameter("actualAmount", chargeDetails.getActualAmount());
                        query.setParameter("id", businessId);
                        query.executeUpdate();
                    } else if (chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_PRODUCT) {
                        // 疗程产品
                        courseProductIds.add(businessId);
                    }
                    // 实付金额充值到疗程中
                    courseAccount = courseAccount.add(chargeDetails.getActualAmount());
                } else if (chargeDetails.getBusinessType() == StateConstants.CHARGE_BUSINESS_TYPE_HOME) {
                    // 家庭病房
                    homeIds.add(businessId);
                    // 判断是否需要生成待交费明细
                    WaitPayment waitPayment = generateWaitPayment(member, chargeDetails, StateConstants.WAIT_PAYMENT_TREAT_TYPE_HOME);
                    if (waitPayment != null) {
                        waitPaymentRepository.save(waitPayment);
                    }
                    // 实付金额充值到病房中
                    StringBuilder sql = new StringBuilder("update treat_plan_home set actual_amount = :actualAmount where id = :id");
                    Query query = em.createNativeQuery(sql.toString());
                    query.setParameter("actualAmount", chargeDetails.getActualAmount());
                    query.setParameter("id", businessId);
                    query.executeUpdate();
                    // 实付金额充值到疗程账户中
                    courseAccount = courseAccount.add(chargeDetails.getActualAmount());
                    // 保存折扣
                    TreatPlanHome ph = treatPlanHomeRepository.findOne(businessId);
                    // 如果不是不限时间，计算过期时间
                    if(ph.getTreatCycle() != 0){
                        Date dd = DateUtils.addYears(new Date(), ph.getTreatCycle());
                        StringBuilder s = new StringBuilder("update treat_plan_home set expired_date = :dm where id = :id");
                        Query nq = em.createNativeQuery(s.toString());
                        nq.setParameter("dm", dd);
                        nq.setParameter("id", ph.getId());
                        nq.executeUpdate();
                    }
                    List<TreatPlanHomeDiscountProduct> dps = discountProductRepository.findByHomeId(businessId);
                    for (TreatPlanHomeDiscountProduct dp : dps) {
                        MemberDiscountProductCategory m = new MemberDiscountProductCategory();
                        m.setPatientId(member.getPatientId());
                        m.setMemberId(member.getId());
                        m.setHomeId(businessId);
                        m.setDiscountName(chargeDetails.getItemName() + "内折扣");
                        m.setDiscountDesc(dp.getCategoryName()+"享受"+dp.getDiscount()+"折优惠");
                        m.setDiscount(dp.getDiscount());
                        m.setCategoryType(dp.getCategoryType());
                        m.setCategoryId(dp.getCategoryId());
                        m.setCategoryName(dp.getCategoryName());
                        BusinessUtil.appendRecord(m);
                        memberDiscountProductCategoryRepository.save(m);
                    }
                    List<TreatPlanHomeDiscountProductDetails> dpds = discountProductDetailsRepository.findByHomeId(businessId);
                    for (TreatPlanHomeDiscountProductDetails dpd : dpds) {
                        MemberDiscountProduct m = new MemberDiscountProduct();
                        m.setPatientId(member.getPatientId());
                        m.setMemberId(member.getId());
                        m.setHomeId(businessId);
                        m.setDiscountName(chargeDetails.getItemName() + "内折扣");
                        m.setDiscountDesc(dpd.getProductName()+"享受"+dpd.getDiscount()+"折优惠");
                        m.setDiscount(dpd.getDiscount());
                        m.setProductId(dpd.getProductId());
                        m.setProductName(dpd.getProductName());
                        BusinessUtil.appendRecord(m);
                        memberDiscountProductRepository.save(m);
                    }
                    List<TreatPlanHomeDiscountProject> dpps = discountProjectRepository.findByHomeId(businessId);
                    for (TreatPlanHomeDiscountProject dpp : dpps) {
                        MemberDiscountProjectType m = new MemberDiscountProjectType();
                        m.setPatientId(member.getPatientId());
                        m.setMemberId(member.getId());
                        m.setHomeId(businessId);
                        m.setDiscountName(chargeDetails.getItemName() + "内折扣");
                        m.setDiscountDesc(dpp.getProjectTypeName()+"享受"+dpp.getDiscount()+"折优惠");
                        m.setDiscount(dpp.getDiscount());
                        m.setProjectTypeId(dpp.getProjectTypeId());
                        m.setProjectTypeName(dpp.getProjectTypeName());
                        BusinessUtil.appendRecord(m);
                        memberDiscountProjectTypeRepository.save(m);
                    }
                    List<TreatPlanHomeDiscountProjectDetails> dpdds = discountProjectDetailsRepository.findByHomeId(businessId);
                    for (TreatPlanHomeDiscountProjectDetails dpdd : dpdds) {
                        MemberDiscountProject m = new MemberDiscountProject();
                        m.setPatientId(member.getPatientId());
                        m.setMemberId(member.getId());
                        m.setHomeId(businessId);
                        m.setDiscountName(chargeDetails.getItemName() + "内折扣");
                        m.setDiscountDesc(dpdd.getProjectName()+"享受"+dpdd.getDiscount()+"折优惠");
                        m.setDiscount(dpdd.getDiscount());
                        m.setProjectId(dpdd.getProjectId());
                        m.setProjectName(dpdd.getProjectName());
                        BusinessUtil.appendRecord(m);
                        memberDiscountProjectRepository.save(m);
                    }
                } else if(chargeDetails.getBusinessType() == StateConstants.CHARGE_BUSINESS_TYPE_SURGICAL){
                    surgicalIds.add(businessId);
                }

                // 单次治疗统计
                if(chargeDetails.getBusinessType() == StateConstants.CHARGE_BUSINESS_TYPE_ONE){
                    // 新诊单次成交人次
                    StringBuilder sql = new StringBuilder("select id from finance_charge_details where member_id = :mid and business_type = :type and charge_status = :status and id != :id");
                    Query q = em.createNativeQuery(sql.toString());
                    q.setParameter("mid", member.getId());
                    q.setParameter("type", StateConstants.CHARGE_BUSINESS_TYPE_ONE);
                    q.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                    q.setParameter("id", chargeDetails.getId());
                    List rs = q.getResultList();
                    // 首次消费
                    if(rs.isEmpty()){
                        // 通过患者查询当天的预约
                        sql = new StringBuilder("select * from business_visit_record where patient_id = :pid and DATE_FORMAT(appointment,'%Y-%m-%d') = :time");
                        q = em.createNativeQuery(sql.toString(),VisitRecord.class);
                        q.setParameter("pid", member.getPatientId());
                        q.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                        List<VisitRecord> rs1 = q.getResultList();
                        if(!rs1.isEmpty()){
                            // 预约当天接待的医护
                            Long doctorId = rs1.get(0).getDoctorId();
                            Long nurseId = rs1.get(0).getNurseId();
                            // 医生
                            sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                            Query nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                            nq.setParameter("id", doctorId);
                            nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                            List<StatisticsFinancial> rs2 = nq.getResultList();
                            if(!rs2.isEmpty()){
                                sql = new StringBuilder("update statistics_financial set new_single_transaction = IFNULL(new_single_transaction,0) + 1 where id = :id");
                                nq = em.createNativeQuery(sql.toString());
                                nq.setParameter("id", rs2.get(0).getId());
                                nq.executeUpdate();
                            }else{
                                User u = mongoUserRepository.findOne(doctorId);
                                StatisticsFinancial sf = new StatisticsFinancial();
                                sf.setUserId(u.getId());
                                sf.setUserName(u.getUsername());
                                sf.setNewSingleTransaction(1);
                                sf.setAccountId(u.getAccountId());
                                sf.setOrganId(u.getOrganId());
                                sf.setOrganName(u.getOrganName());
                                BusinessUtil.appendRecord(sf);
                                statisticsFinancialRepository.save(sf);
                            }
                            // 护士
                            sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                            nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                            nq.setParameter("id", nurseId);
                            nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                            rs2 = nq.getResultList();
                            if(!rs2.isEmpty()){
                                sql = new StringBuilder("update statistics_financial set new_single_transaction = IFNULL(new_single_transaction,0) + 1 where id = :id");
                                nq = em.createNativeQuery(sql.toString());
                                nq.setParameter("id", rs2.get(0).getId());
                                nq.executeUpdate();
                            }else{
                                User u = mongoUserRepository.findOne(nurseId);
                                StatisticsFinancial sf = new StatisticsFinancial();
                                sf.setUserId(u.getId());
                                sf.setUserName(u.getUsername());
                                sf.setNewSingleTransaction(1);
                                sf.setAccountId(u.getAccountId());
                                sf.setOrganId(u.getOrganId());
                                sf.setOrganName(u.getOrganName());
                                BusinessUtil.appendRecord(sf);
                                statisticsFinancialRepository.save(sf);
                            }
                        }
                    }else{
                        // 复诊单次再消费人次
                        sql = new StringBuilder("select * from finance_charge_details where member_id = :mid and business_type = :type and charge_status = :status and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                        q = em.createNativeQuery(sql.toString());
                        q.setParameter("mid", member.getId());
                        q.setParameter("type", StateConstants.CHARGE_BUSINESS_TYPE_ONE);
                        q.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                        q.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                        rs = q.getResultList();
                        sql = new StringBuilder("select * from finance_charge_details where member_id = :mid and business_type = :type and charge_status = :status and DATE_FORMAT(creation_time,'%Y-%m-%d') < :time");
                        q = em.createNativeQuery(sql.toString());
                        q.setParameter("mid", member.getId());
                        q.setParameter("type", StateConstants.CHARGE_BUSINESS_TYPE_ONE);
                        q.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                        q.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                        List rs0 = q.getResultList();
                        // 如果当天还没有消费则累计加1
                        if((rs0.isEmpty() && rs.size() == 1)||(!rs0.isEmpty() && rs.isEmpty())){
                            // 通过患者查询当天的预约
                            sql = new StringBuilder("select * from business_visit_record where patient_id = :pid and DATE_FORMAT(appointment,'%Y-%m-%d') = :time");
                            q = em.createNativeQuery(sql.toString(),VisitRecord.class);
                            q.setParameter("pid", member.getPatientId());
                            q.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                            List<VisitRecord> rs1 = q.getResultList();
                            if(!rs1.isEmpty()) {
                                // 预约当天接待的医护
                                Long doctorId = rs1.get(0).getDoctorId();
                                Long nurseId = rs1.get(0).getNurseId();
                                // 医生
                                sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                                Query nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                                nq.setParameter("id", doctorId);
                                nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                                List<StatisticsFinancial> rs2 = nq.getResultList();
                                if(!rs2.isEmpty()){
                                    sql = new StringBuilder("update statistics_financial set review_single_transaction = IFNULL(review_single_transaction,0) + 1 where id = :id");
                                    nq = em.createNativeQuery(sql.toString());
                                    nq.setParameter("id", rs2.get(0).getId());
                                    nq.executeUpdate();
                                }else{
                                    User u = mongoUserRepository.findOne(doctorId);
                                    StatisticsFinancial sf = new StatisticsFinancial();
                                    sf.setUserId(u.getId());
                                    sf.setUserName(u.getUsername());
                                    sf.setReviewSingleTransaction(1);
                                    sf.setAccountId(u.getAccountId());
                                    sf.setOrganId(u.getOrganId());
                                    sf.setOrganName(u.getOrganName());
                                    BusinessUtil.appendRecord(sf);
                                    statisticsFinancialRepository.save(sf);
                                }
                                // 护士
                                sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                                nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                                nq.setParameter("id", nurseId);
                                nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                                rs2 = nq.getResultList();
                                if(!rs2.isEmpty()){
                                    sql = new StringBuilder("update statistics_financial set review_single_transaction = IFNULL(review_single_transaction,0) + 1 where id = :id");
                                    nq = em.createNativeQuery(sql.toString());
                                    nq.setParameter("id", rs2.get(0).getId());
                                    nq.executeUpdate();
                                }else{
                                    User u = mongoUserRepository.findOne(nurseId);
                                    StatisticsFinancial sf = new StatisticsFinancial();
                                    sf.setUserId(u.getId());
                                    sf.setUserName(u.getUsername());
                                    sf.setReviewSingleTransaction(1);
                                    sf.setAccountId(u.getAccountId());
                                    sf.setOrganId(u.getOrganId());
                                    sf.setOrganName(u.getOrganName());
                                    BusinessUtil.appendRecord(sf);
                                    statisticsFinancialRepository.save(sf);
                                }
                            }
                        }
                        // 复诊单次再消费金额
                        // 通过患者查询当天的预约
                        sql = new StringBuilder("select * from business_visit_record where patient_id = :pid and DATE_FORMAT(appointment,'%Y-%m-%d') = :time");
                        q = em.createNativeQuery(sql.toString(),VisitRecord.class);
                        q.setParameter("pid", member.getPatientId());
                        q.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                        List<VisitRecord> rs1 = q.getResultList();
                        if(!rs1.isEmpty()) {
                            // 预约当天接待的医护
                            Long doctorId = rs1.get(0).getDoctorId();
                            Long nurseId = rs1.get(0).getNurseId();
                            // 医生
                            sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                            Query nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                            nq.setParameter("id", doctorId);
                            nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                            List<StatisticsFinancial> rs2 = nq.getResultList();
                            if(!rs2.isEmpty()){
                                sql = new StringBuilder("update statistics_financial set review_single_reamount = IFNULL(review_single_reamount,0) + :amount where id = :id");
                                nq = em.createNativeQuery(sql.toString());
                                nq.setParameter("amount", chargeDetails.getActualAmount());
                                nq.setParameter("id", rs2.get(0).getId());
                                nq.executeUpdate();
                            }else{
                                User u = mongoUserRepository.findOne(doctorId);
                                StatisticsFinancial sf = new StatisticsFinancial();
                                sf.setUserId(u.getId());
                                sf.setUserName(u.getUsername());
                                sf.setReviewSingleReamount(chargeDetails.getActualAmount());
                                sf.setAccountId(u.getAccountId());
                                sf.setOrganId(u.getOrganId());
                                sf.setOrganName(u.getOrganName());
                                BusinessUtil.appendRecord(sf);
                                statisticsFinancialRepository.save(sf);
                            }
                            // 护士
                            sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                            nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                            nq.setParameter("id", nurseId);
                            nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                            rs2 = nq.getResultList();
                            if(!rs2.isEmpty()){
                                sql = new StringBuilder("update statistics_financial set review_single_reamount = IFNULL(review_single_reamount,0) + :amount where id = :id");
                                nq = em.createNativeQuery(sql.toString());
                                nq.setParameter("amount", chargeDetails.getActualAmount());
                                nq.setParameter("id", rs2.get(0).getId());
                                nq.executeUpdate();
                            }else{
                                User u = mongoUserRepository.findOne(nurseId);
                                StatisticsFinancial sf = new StatisticsFinancial();
                                sf.setUserId(u.getId());
                                sf.setUserName(u.getUsername());
                                sf.setReviewSingleReamount(chargeDetails.getActualAmount());
                                sf.setAccountId(u.getAccountId());
                                sf.setOrganId(u.getOrganId());
                                sf.setOrganName(u.getOrganName());
                                BusinessUtil.appendRecord(sf);
                                statisticsFinancialRepository.save(sf);
                            }
                        }
                    }
                    // 新诊单次成交金额
                    sql = new StringBuilder("select * from finance_charge_details where member_id = :mid and business_type = :type and charge_status = :status and creation_time <= :time");
                    q = em.createNativeQuery(sql.toString());
                    q.setParameter("mid", member.getId());
                    q.setParameter("type", StateConstants.CHARGE_BUSINESS_TYPE_ONE);
                    q.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                    q.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd") + " 23:59:59");
                    rs = q.getResultList();
                    if(rs.isEmpty()){
                        // 通过患者查询当天的预约
                        sql = new StringBuilder("select * from business_visit_record where patient_id = :pid and DATE_FORMAT(appointment,'%Y-%m-%d') = :time");
                        q = em.createNativeQuery(sql.toString(),VisitRecord.class);
                        q.setParameter("pid", member.getPatientId());
                        q.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                        List<VisitRecord> rs1 = q.getResultList();
                        if(!rs1.isEmpty()) {
                            // 预约当天接待的医护
                            Long doctorId = rs1.get(0).getDoctorId();
                            Long nurseId = rs1.get(0).getNurseId();
                            // 医生
                            sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                            Query nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                            nq.setParameter("id", doctorId);
                            nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                            List<StatisticsFinancial> rs2 = nq.getResultList();
                            if(!rs2.isEmpty()){
                                sql = new StringBuilder("update statistics_financial set new_single_amount = IFNULL(new_single_amount,0) + :amount where id = :id");
                                nq = em.createNativeQuery(sql.toString());
                                nq.setParameter("amount", chargeDetails.getActualAmount());
                                nq.setParameter("id", rs2.get(0).getId());
                                nq.executeUpdate();
                            }else{
                                User u = mongoUserRepository.findOne(doctorId);
                                StatisticsFinancial sf = new StatisticsFinancial();
                                sf.setUserId(u.getId());
                                sf.setUserName(u.getUsername());
                                sf.setNewSingleAmount(chargeDetails.getActualAmount());
                                sf.setAccountId(u.getAccountId());
                                sf.setOrganId(u.getOrganId());
                                sf.setOrganName(u.getOrganName());
                                BusinessUtil.appendRecord(sf);
                                statisticsFinancialRepository.save(sf);
                            }

                            sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                            nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                            nq.setParameter("id", nurseId);
                            nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                            rs2 = nq.getResultList();
                            if(!rs2.isEmpty()){
                                sql = new StringBuilder("update statistics_financial set new_single_amount = IFNULL(new_single_amount,0) + :amount where id = :id");
                                nq = em.createNativeQuery(sql.toString());
                                nq.setParameter("amount", chargeDetails.getActualAmount());
                                nq.setParameter("id", rs2.get(0).getId());
                                nq.executeUpdate();
                            }else{
                                User u = mongoUserRepository.findOne(nurseId);
                                StatisticsFinancial sf = new StatisticsFinancial();
                                sf.setUserId(u.getId());
                                sf.setUserName(u.getUsername());
                                sf.setNewSingleAmount(chargeDetails.getActualAmount());
                                sf.setAccountId(u.getAccountId());
                                sf.setOrganId(u.getOrganId());
                                sf.setOrganName(u.getOrganName());
                                BusinessUtil.appendRecord(sf);
                                statisticsFinancialRepository.save(sf);
                            }
                        }
                    }
                }

                // 疗程&家庭病房统计
                if (chargeDetails.getBusinessType() == StateConstants.CHARGE_BUSINESS_TYPE_COURSE
                        || chargeDetails.getBusinessType() == StateConstants.CHARGE_BUSINESS_TYPE_HOME) {
                    if(chargeDetails.getIsRenew() == 0){
                        // 新诊疗程成交人次
                        // 校验付款记录
                        StringBuilder sql = new StringBuilder("select * from finance_charge_details where member_id = :mid and charge_status = :status and id != :id and (business_type = :type1 or business_type = :type2)");
                        Query q = em.createNativeQuery(sql.toString());
                        q.setParameter("mid", member.getId());
                        q.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                        q.setParameter("id", chargeDetails.getId());
                        q.setParameter("type1", StateConstants.CHARGE_BUSINESS_TYPE_COURSE);
                        q.setParameter("type2", StateConstants.CHARGE_BUSINESS_TYPE_HOME);
                        List rs = q.getResultList();
                        // 首次消费
                        if(rs.isEmpty()){
                            // 通过患者查询当天的预约
                            sql = new StringBuilder("select * from business_visit_record where patient_id = :pid and DATE_FORMAT(appointment,'%Y-%m-%d') = :time");
                            q = em.createNativeQuery(sql.toString(),VisitRecord.class);
                            q.setParameter("pid", member.getPatientId());
                            q.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                            List<VisitRecord> rs1 = q.getResultList();
                            if(!rs1.isEmpty()){
                                // 预约当天接待的医护
                                Long doctorId = rs1.get(0).getDoctorId();
                                Long nurseId = rs1.get(0).getNurseId();
                                // 医生
                                sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                                Query nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                                nq.setParameter("id", doctorId);
                                nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                                List<StatisticsFinancial> rs2 = nq.getResultList();
                                if(!rs2.isEmpty()){
                                    sql = new StringBuilder("update statistics_financial set new_course_transaction = IFNULL(new_course_transaction,0) + 1 where id = :id");
                                    nq = em.createNativeQuery(sql.toString());
                                    nq.setParameter("id", rs2.get(0).getId());
                                    nq.executeUpdate();
                                }else{
                                    User u = mongoUserRepository.findOne(doctorId);
                                    StatisticsFinancial sf = new StatisticsFinancial();
                                    sf.setUserId(u.getId());
                                    sf.setUserName(u.getUsername());
                                    sf.setNewCourseTransaction(1);
                                    sf.setAccountId(u.getAccountId());
                                    sf.setOrganId(u.getOrganId());
                                    sf.setOrganName(u.getOrganName());
                                    BusinessUtil.appendRecord(sf);
                                    statisticsFinancialRepository.save(sf);
                                }
                                // 护士
                                sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                                nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                                nq.setParameter("id", nurseId);
                                nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                                rs2 = nq.getResultList();
                                if(!rs2.isEmpty()){
                                    sql = new StringBuilder("update statistics_financial set new_course_transaction = IFNULL(new_course_transaction,0) + 1 where id = :id");
                                    nq = em.createNativeQuery(sql.toString());
                                    nq.setParameter("id", rs2.get(0).getId());
                                    nq.executeUpdate();
                                }else{
                                    User u = mongoUserRepository.findOne(nurseId);
                                    StatisticsFinancial sf = new StatisticsFinancial();
                                    sf.setUserId(u.getId());
                                    sf.setUserName(u.getUsername());
                                    sf.setNewCourseTransaction(1);
                                    sf.setAccountId(u.getAccountId());
                                    sf.setOrganId(u.getOrganId());
                                    sf.setOrganName(u.getOrganName());
                                    BusinessUtil.appendRecord(sf);
                                    statisticsFinancialRepository.save(sf);
                                }
                            }
                        }
                        // 新诊疗程金额统计
                        sql = new StringBuilder("select * from finance_charge_details where member_id = :mid and charge_status = :status and creation_time <= :time and (business_type = :type1 or business_type = :type2)");
                        q = em.createNativeQuery(sql.toString());
                        q.setParameter("mid", member.getId());
                        q.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                        q.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd") + " 23:59:59");
                        q.setParameter("type1", StateConstants.CHARGE_BUSINESS_TYPE_COURSE);
                        q.setParameter("type2", StateConstants.CHARGE_BUSINESS_TYPE_HOME);
                        rs = q.getResultList();
                        if(rs.isEmpty()){
                            // 通过患者查询当天的预约
                            sql = new StringBuilder("select * from business_visit_record where patient_id = :pid and DATE_FORMAT(appointment,'%Y-%m-%d') = :time");
                            q = em.createNativeQuery(sql.toString(),VisitRecord.class);
                            q.setParameter("pid", member.getPatientId());
                            q.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                            List<VisitRecord> rs1 = q.getResultList();
                            if(!rs1.isEmpty()) {
                                // 预约当天接待的医护
                                Long doctorId = rs1.get(0).getDoctorId();
                                Long nurseId = rs1.get(0).getNurseId();

                                sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                                Query nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                                nq.setParameter("id", doctorId);
                                nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                                List<StatisticsFinancial> rs2 = nq.getResultList();
                                if(!rs2.isEmpty()){
                                    sql = new StringBuilder("update statistics_financial set new_course_amount = IFNULL(new_course_amount,0) + :amount where id = :id");
                                    nq = em.createNativeQuery(sql.toString());
                                    nq.setParameter("amount", chargeDetails.getActualAmount());
                                    nq.setParameter("id", rs2.get(0).getId());
                                    nq.executeUpdate();
                                }else{
                                    User u = mongoUserRepository.findOne(doctorId);
                                    StatisticsFinancial sf = new StatisticsFinancial();
                                    sf.setUserId(u.getId());
                                    sf.setUserName(u.getUsername());
                                    sf.setNewCourseAmount(chargeDetails.getActualAmount());
                                    sf.setAccountId(u.getAccountId());
                                    sf.setOrganId(u.getOrganId());
                                    sf.setOrganName(u.getOrganName());
                                    BusinessUtil.appendRecord(sf);
                                    statisticsFinancialRepository.save(sf);
                                }

                                sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                                nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                                nq.setParameter("id", nurseId);
                                nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                                rs2 = nq.getResultList();
                                if(!rs2.isEmpty()){
                                    sql = new StringBuilder("update statistics_financial set new_course_amount = IFNULL(new_course_amount,0) + :amount where id = :id");
                                    nq = em.createNativeQuery(sql.toString());
                                    nq.setParameter("amount", chargeDetails.getActualAmount());
                                    nq.setParameter("id", rs2.get(0).getId());
                                    nq.executeUpdate();
                                }else{
                                    User u = mongoUserRepository.findOne(nurseId);
                                    StatisticsFinancial sf = new StatisticsFinancial();
                                    sf.setUserId(u.getId());
                                    sf.setUserName(u.getUsername());
                                    sf.setNewCourseAmount(chargeDetails.getActualAmount());
                                    sf.setAccountId(u.getAccountId());
                                    sf.setOrganId(u.getOrganId());
                                    sf.setOrganName(u.getOrganName());
                                    BusinessUtil.appendRecord(sf);
                                    statisticsFinancialRepository.save(sf);
                                }
                            }
                        }
                    }else if(chargeDetails.getIsRenew() == 1){
                        // 续家庭病房
                        if(chargeDetails.getBusinessType() == StateConstants.CHARGE_BUSINESS_TYPE_HOME){
                            // 通过患者查询当天的预约
                            StringBuilder sql = new StringBuilder("select * from business_visit_record where patient_id = :pid and DATE_FORMAT(appointment,'%Y-%m-%d') = :time");
                            Query q = em.createNativeQuery(sql.toString(),VisitRecord.class);
                            q.setParameter("pid", member.getPatientId());
                            q.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                            List<VisitRecord> rs = q.getResultList();
                            if(!rs.isEmpty()){
                                // 预约当天接待的医护
                                Long doctorId = rs.get(0).getDoctorId();
                                Long nurseId = rs.get(0).getNurseId();

                                sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                                Query nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                                nq.setParameter("id", doctorId);
                                nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                                List<StatisticsFinancial> rs1 = nq.getResultList();
                                if(!rs1.isEmpty()){
                                    sql = new StringBuilder("update statistics_financial set review_renewal_course_transaction = IFNULL(review_renewal_course_transaction,0) + 1,review_renewal_course_amount = IFNULL(review_renewal_course_amount,0) + :amount where id = :id");
                                    nq = em.createNativeQuery(sql.toString());
                                    nq.setParameter("amount", chargeDetails.getActualAmount());
                                    nq.setParameter("id", rs1.get(0).getId());
                                    nq.executeUpdate();
                                }else{
                                    User u = mongoUserRepository.findOne(doctorId);
                                    StatisticsFinancial sf = new StatisticsFinancial();
                                    sf.setUserId(u.getId());
                                    sf.setUserName(u.getUsername());
                                    sf.setReviewRenewalCourseTransaction(1);
                                    sf.setReviewRenewalCourseAmount(chargeDetails.getActualAmount());
                                    sf.setAccountId(u.getAccountId());
                                    sf.setOrganId(u.getOrganId());
                                    sf.setOrganName(u.getOrganName());
                                    BusinessUtil.appendRecord(sf);
                                    statisticsFinancialRepository.save(sf);
                                }

                                sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                                nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                                nq.setParameter("id", nurseId);
                                nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                                rs1 = nq.getResultList();
                                if(!rs1.isEmpty()){
                                    sql = new StringBuilder("update statistics_financial set review_renewal_course_transaction = IFNULL(review_renewal_course_transaction,0) + 1,review_renewal_course_amount = IFNULL(review_renewal_course_amount,0) + :amount where id = :id");
                                    nq = em.createNativeQuery(sql.toString());
                                    nq.setParameter("amount", chargeDetails.getActualAmount());
                                    nq.setParameter("id", rs1.get(0).getId());
                                    nq.executeUpdate();
                                }else{
                                    User u = mongoUserRepository.findOne(nurseId);
                                    StatisticsFinancial sf = new StatisticsFinancial();
                                    sf.setUserId(u.getId());
                                    sf.setUserName(u.getUsername());
                                    sf.setReviewRenewalCourseTransaction(1);
                                    sf.setReviewRenewalCourseAmount(chargeDetails.getActualAmount());
                                    sf.setAccountId(u.getAccountId());
                                    sf.setOrganId(u.getOrganId());
                                    sf.setOrganName(u.getOrganName());
                                    BusinessUtil.appendRecord(sf);
                                    statisticsFinancialRepository.save(sf);
                                }
                            }
                        }
                    }
                }

                // 生成消费明细
                ConsumeDetailsRecord consumeDetailsRecord = new ConsumeDetailsRecord();
                consumeDetailsRecord.setRecordId(consumeRecord.getId());
                consumeDetailsRecord.setBusinessId(chargeDetails.getBusinessId());
                consumeDetailsRecord.setItemId(chargeDetails.getItemId());
                consumeDetailsRecord.setItemName(chargeDetails.getItemName());
                consumeDetailsRecord.setPayAmount(chargeDetails.getTotalPrice());
                consumeDetailsRecord.setDiscount(chargeDetails.getDiscount());
                consumeDetailsRecord.setDiscountAmount(chargeDetails.getDiscountAmount());
                consumeDetailsRecord.setActualAmount(chargeDetails.getActualAmount());
                consumeDetailsRecord.setQuantity(chargeDetails.getQuantity());
                consumeDetailsRecord.setCardNumber(chargeDetails.getCardNumber());
                consumeDetailsRecordRepository.save(consumeDetailsRecord);
            }

            // 更新单次项目付费状态
            if (!projectIds.isEmpty()) {
                StringBuilder sql = new StringBuilder("update treat_plan_project set charge_status = :status where id in(:ids)");
                Query query = em.createNativeQuery(sql.toString());
                query.setParameter("ids", projectIds);
                query.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                query.executeUpdate();
            }
            // 更新单次产品付费状态
            if (!productIds.isEmpty()) {
                StringBuilder sql = new StringBuilder("update treat_plan_product set charge_status = :status where id in(:ids)");
                Query query = em.createNativeQuery(sql.toString());
                query.setParameter("ids", productIds);
                query.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                query.executeUpdate();
            }
            // 更新服务费付费状态
            if (!serviceIds.isEmpty()) {
                StringBuilder sql = new StringBuilder("update treat_plan_service_project set charge_status = :status where id in(:ids)");
                Query query = em.createNativeQuery(sql.toString());
                query.setParameter("ids", serviceIds);
                query.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                query.executeUpdate();
            }
            // 更新长期疗程付费状态
            if (!courseIds.isEmpty()) {
                StringBuilder sql = new StringBuilder("update treat_plan_course set charge_status = :status where id in(:ids)");
                Query query = em.createNativeQuery(sql.toString());
                query.setParameter("ids", courseIds);
                query.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                query.executeUpdate();
            }
            // 更新长期产品付费状态
            if (!courseProductIds.isEmpty()) {
                StringBuilder sql = new StringBuilder("update treat_plan_course_product set charge_status = :status where id in(:ids)");
                Query query = em.createNativeQuery(sql.toString());
                query.setParameter("ids", courseProductIds);
                query.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                query.executeUpdate();
            }
            // 更新家庭病房付费状态
            if (!homeIds.isEmpty()) {
                StringBuilder sql = new StringBuilder("update treat_plan_home set charge_status = :status where id in(:ids)");
                Query query = em.createNativeQuery(sql.toString());
                query.setParameter("ids", homeIds);
                query.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                query.executeUpdate();
            }
            // 更新外科付费状态
            if(!surgicalIds.isEmpty()){
                StringBuilder sql = new StringBuilder("update treat_plan_surgical_project set charge_status = :status where id in(:ids)");
                Query query = em.createNativeQuery(sql.toString());
                query.setParameter("ids", surgicalIds);
                query.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                query.executeUpdate();
            }
            // 更新待付款明细付费状态
            if (!chargeIds.isEmpty()) {
                StringBuilder sql = new StringBuilder("update finance_charge_details set charge_status = :status where id in(:ids)");
                Query query = em.createNativeQuery(sql.toString());
                query.setParameter("ids", chargeIds);
                query.setParameter("status", StateConstants.CHARGE_STATUS_YES);
                query.executeUpdate();
            }
            // 更新服务费抵扣状态
            if (!ids.isEmpty()) {
                StringBuilder sql = new StringBuilder("update treat_plan_service_project set deduct_status = :status,deduct_time = :time where id in(:ids)");
                Query query = em.createNativeQuery(sql.toString());
                query.setParameter("status", StateConstants.DEDUCT_STATUS_YES);
                query.setParameter("time", new Date());
                query.setParameter("ids", ids);
                query.executeUpdate();
            }

            // 保存支付信息
            paymentDetails.setRecordId(consumeRecord.getId());
            paymentDetails.setRecordType(StateConstants.RECORD_TYPE_CONSUME);
            BusinessUtil.appendRecord(paymentDetails);
            paymentDetailsRepository.save(paymentDetails);

            // 更新会员信息
            member.setCourseAccount(courseAccount);
            BusinessUtil.appendRecord(member);
            memberRepository.save(member);

            // 记录账户变动后的信息
            afterAccount(changeDetails, member);
            changeDetails.setRecordId(consumeRecord.getId());
            changeDetails.setRecordType(StateConstants.RECORD_TYPE_CONSUME);
            // 保存账户变动
            accountChangeDetailsRepository.save(changeDetails);
        }
        // 判断是否打印小票
        int autoPrint = checkPrint();
        Map<String, Object> params = new HashMap();
        if(autoPrint == StateConstants.AUTO_PRINT_YES){
            JSONObject json = new JSONObject();
            JSONArray ja = new JSONArray();
            for (ChargeDetails record : records) {
                JSONObject jo = new JSONObject();
                jo.put("itemName", record.getItemName());
                jo.put("totalPrice", record.getTotalPrice());
                jo.put("actualPayAmount", record.getActualAmount());
                jo.put("discountRate", record.getDiscount().equals(0d) ? null : record.getDiscount());
                jo.put("quantity", record.getQuantity());
                ja.add(jo);
            }
            json.put("details", ja);
            json.put("medicalNumber", member.getMemberNumber());
            json.put("memberName", member.getMemberName());
            json.put("afterLevelName", member.getLevelName());
            json.put("payType", StateConstants.PRINT_PAY_TYPE_PAYMENT);
            json.put("afterStoreAccount", member.getStoreAccount());
            json.put("afterGiftAccount", member.getGiftAccount());
            json.put("afterTreatAccount", member.getCourseAccount());
            json.put("actualPayAmount", payInfo.getActualAmount());
            json.put("storedAccount", paymentDetails.getStore());
            json.put("giftAccount", paymentDetails.getGift());
            json.put("bankCard", paymentDetails.getBankCard());
            json.put("alipay", paymentDetails.getAlipay());
            json.put("wechat", paymentDetails.getWechat());
            json.put("cash", paymentDetails.getCash());
            json.put("creationTime", DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            json.put("createdBy", RequestUtil.getLoginUser().getUsername());
            params.put("task", json);
        }
        params.put("autoPrint", autoPrint);
        result.setParams(params);
        return result;
    }

    public Result validPayAmount(Result result, PayInfo payInfo, PaymentDetails paymentDetails) {
        // 应付金额
        BigDecimal actualAmount = payInfo.getActualAmount();
        // 实付金额
        BigDecimal payAmount = BigDecimal.ZERO;
        if (paymentDetails.getStore() != null) {
            payAmount = payAmount.add(paymentDetails.getStore());
        }
        if (paymentDetails.getGift() != null) {
            payAmount = payAmount.add(paymentDetails.getGift());
        }
        if (paymentDetails.getAlipay() != null) {
            payAmount = payAmount.add(paymentDetails.getAlipay());
        }
        if (paymentDetails.getWechat() != null) {
            payAmount = payAmount.add(paymentDetails.getWechat());
        }
        if (paymentDetails.getBankCard() != null) {
            payAmount = payAmount.add(paymentDetails.getBankCard());
        }
        if (paymentDetails.getCash() != null) {
            payAmount = payAmount.add(paymentDetails.getCash());
        }
        // 校验付款金额是否和应付金额相等
        if (actualAmount.compareTo(payAmount) != 0) {
            result.setCode(CommonConstants.FAILURE);
            result.setMsg("请确认付款金额");
        }
        return result;
    }

    public Result validMemberAccount(Result result, Member member, PaymentDetails paymentDetails) {
        // 储值账户付款
        BigDecimal store = paymentDetails.getStore();
        if (store != null && store.compareTo(BigDecimal.ZERO) > 0) {
            // 会员储值账户剩余金额
            BigDecimal storeAccount = member.getStoreAccount();
            // 校验余额是否充足
            if (storeAccount.compareTo(store) < 0) {
                result.setCode(CommonConstants.FAILURE);
                result.setMsg("储值账户余额不足");
                return result;
            }
            // 会员储值账户扣减
            member.setStoreAccount(storeAccount.subtract(store));
        }
        // 赠送账户付款
        BigDecimal gift = paymentDetails.getGift();
        if (gift != null && gift.compareTo(BigDecimal.ZERO) > 0) {
            // 会员赠送账户
            BigDecimal giftAccount = member.getGiftAccount();
            // 校验赠送账户
            if (giftAccount.compareTo(gift) < 0) {
                result.setCode(CommonConstants.FAILURE);
                result.setMsg("赠送账户余额不足");
                return result;
            }
            // 会员赠送账户扣减
            member.setGiftAccount(giftAccount.subtract(gift));
        }
        return result;
    }

    public Result validInventory(Result result, Map<Long, Map<String, Integer>> map) {
        StringBuilder msg = new StringBuilder("");
        for (Map.Entry<Long, Map<String, Integer>> entry1 : map.entrySet()) {
            Map<String, Integer> valueMap = entry1.getValue();
            for (Map.Entry<String, Integer> entry2 : valueMap.entrySet()) {
                Long itemId = entry1.getKey();
                String itemName = entry2.getKey();
                Inventory inventory = inventoryRepository.findByItemId(itemId);
                if (inventory == null) {
                    msg.append("商品[" + itemName + "]还未生成库存");
                    continue;
                }
                // 预扣减库存
                int quantity = entry2.getValue().intValue();
                // 可用库存
                int useInventory = inventory.getUseInventory();
                if (quantity > useInventory) {
                    msg.append("商品[" + itemName + "]可用库存不足");
                    continue;
                }
            }
        }
        if (!msg.toString().equals("")) {
            result.setCode(CommonConstants.FAILURE);
            result.setMsg(msg.toString());
        }
        return result;
    }

    public WaitPayment generateWaitPayment(Member member, ChargeDetails chargeDetails, int type) {
        // 应付金额
        BigDecimal totalPrice = chargeDetails.getTotalPrice();
        // 实付金额
        BigDecimal actualAmount = chargeDetails.getActualAmount();
        // 如果实付金额小于应付金额
        if (actualAmount.compareTo(totalPrice) < 0) {
            // 生成待缴费明细
            WaitPayment waitPayment = new WaitPayment();
            waitPayment.setPatientId(member.getPatientId());
            waitPayment.setMemberId(member.getId());
            waitPayment.setMemberName(member.getMemberName());
            waitPayment.setBusinessId(chargeDetails.getBusinessId());
            waitPayment.setBusinessName(chargeDetails.getItemName());
            waitPayment.setBusinessType(type);
            waitPayment.setPrice(chargeDetails.getPrice());
            waitPayment.setQuantity(chargeDetails.getQuantity());
            waitPayment.setTotalAmount(chargeDetails.getTotalPrice());
            waitPayment.setPayAmount(actualAmount);
            BusinessUtil.appendRecord(waitPayment);
            return waitPayment;
        }
        return null;
    }

    @Override
    @Transactional
    public Result doDeduct(List<DeductRecord> records) {
        Result result = new Result();
        result.setCode(CommonConstants.SUCCESS);
        result.setMsg("操作成功");
        BigDecimal totalDeductAmount = BigDecimal.ZERO;
        Member member = memberRepository.findOne(records.get(0).getMemberId());
        if (member != null) {
            // 会员疗程账户
            BigDecimal courseAccount = member.getCourseAccount();
            // 同一疗程统一处理
            Map<Long, List<DeductRecord>> courseMap = new HashMap<>();
            // 同一病房统一处理
            Map<Long, List<DeductRecord>> homeMap = new HashMap<>();
            for (DeductRecord record : records) {
                totalDeductAmount = totalDeductAmount.add(record.getDeductAmount());
                // 先分类
                int treatType = record.getTreatType();
                if (treatType == StateConstants.TREAT_TYPE_COURSE_PRODUCT) {
                    // 账户变动信息
                    AccountChangeDetails changeDetails = new AccountChangeDetails();
                    // 记录充值前账户信息
                    beforeAccount(changeDetails, member);
                    // 记录划扣前疗程金额
                    changeDetails.setBeforeCourseAccount(courseAccount);
                    // 业务关联主键
                    Long businessId = record.getBusinessId();
                    // 本次划扣次数
                    int thisDeductCount = record.getDeductCount();
                    // 本次划扣金额
                    BigDecimal thisDeductAmount = record.getDeductAmount();
                    // 先获取业务关联数据
                    TreatPlanCourseProduct courseProduct = treatPlanCourseProductRepository.findOne(businessId);
                    courseProduct.setDeduct(courseProduct.getDeduct() + thisDeductCount);
                    courseProduct.setExecuteStatus(StateConstants.EXECUTE_STATUS_NO);
                    BigDecimal deductAmount = courseProduct.getDeductAmount() == null ? BigDecimal.ZERO : courseProduct.getDeductAmount();
                    BigDecimal temp = deductAmount.add(thisDeductAmount);
                    // 如果本次划扣金额+已划扣金额>疗程总价
                    if (temp.compareTo(courseProduct.getTotalPrice()) > 0) {
                        // 本次划扣金额就等于疗程剩余可划扣金额
                        thisDeductAmount = courseProduct.getTotalPrice().subtract(deductAmount);
                    }
                    deductAmount = deductAmount.add(thisDeductAmount);
                    courseProduct.setDeductAmount(deductAmount);
                    BusinessUtil.appendRecord(courseProduct);
                    treatPlanCourseProductRepository.save(courseProduct);
                    // 保存划扣记录
                    record.setMemberName(member.getMemberName());
                    record.setMemberNumber(member.getMemberNumber());
                    record.setDeductAmount(thisDeductAmount);
                    BusinessUtil.appendRecord(record);
                    deductRecordRepository.save(record);
                    // 从疗程账户中减去本次划扣金额
                    courseAccount = courseAccount.subtract(thisDeductAmount);

                    // 记录账户变动后的信息
                    afterAccount(changeDetails, member);
                    changeDetails.setAfterCourseAccount(courseAccount);
                    changeDetails.setRecordId(record.getId());
                    changeDetails.setRecordType(StateConstants.RECORD_TYPE_DEDUCT);
                    // 保存账户变动
                    accountChangeDetailsRepository.save(changeDetails);
                } else if (treatType == StateConstants.TREAT_TYPE_COURSE_DETAILS) {
                    if (courseMap.containsKey(record.getTreatId())) {
                        courseMap.get(record.getTreatId()).add(record);
                    } else {
                        List<DeductRecord> list = new ArrayList<>();
                        list.add(record);
                        courseMap.put(record.getTreatId(), list);
                    }
                } else if (treatType == StateConstants.TREAT_TYPE_HOME_PROJECT || treatType == StateConstants.TREAT_TYPE_HOME_PRODUCT) {
                    if (homeMap.containsKey(record.getTreatId())) {
                        homeMap.get(record.getTreatId()).add(record);
                    } else {
                        List<DeductRecord> list = new ArrayList<>();
                        list.add(record);
                        homeMap.put(record.getTreatId(), list);
                    }
                }
            }
            // 疗程划扣处理
            for (Map.Entry<Long, List<DeductRecord>> entry : courseMap.entrySet()) {
                Long courseId = entry.getKey();
                TreatPlanCourse course = treatPlanCourseRepository.findOne(courseId);
                // 已划扣金额
                BigDecimal deductAmount = course.getDeductAmount() == null ? BigDecimal.ZERO : course.getDeductAmount();
                List<DeductRecord> list = entry.getValue();
                for (DeductRecord deductRecord : list) {
                    // 账户变动信息
                    AccountChangeDetails changeDetails = new AccountChangeDetails();
                    // 记录充值前账户信息
                    beforeAccount(changeDetails, member);
                    // 记录划扣前疗程金额
                    changeDetails.setBeforeCourseAccount(courseAccount);
                    // 关联业务主键
                    Long id = deductRecord.getBusinessId();
                    // 本次划扣次数
                    int thisDeductCount = deductRecord.getDeductCount();
                    // 本次划扣金额
                    BigDecimal thisDeductAmount = deductRecord.getDeductAmount();
                    // 疗程应付
                    BigDecimal totalPrice = course.getTotalPrice();
                    // 疗程实付
                    BigDecimal actualAmount = course.getActualAmount();
                    // 划扣金额=已划扣金额+本次划扣金额
                    BigDecimal temp = deductAmount.add(thisDeductAmount);
                    // 欠费模式
                    // 如果疗程实付小于疗程应付
                    if (actualAmount.compareTo(totalPrice) < 0) {
                        // 如果本次划扣已超过疗程实付金额
                        if (temp.compareTo(actualAmount) >= 0) {
                            // 提示已超出
                            result.setCode(CommonConstants.FAILURE);
                            result.setMsg(deductRecord.getItemName() + "预划扣金额不足，请先交费");
                            return result;
                        }
                        // 非欠费模式
                    } else {
                        // 如果本次划扣已超过疗程实付金额
                        if (temp.compareTo(totalPrice) > 0) {
                            // 本次划扣金额即剩余可划扣金额或者按0划扣
                            thisDeductAmount = course.getTotalPrice().subtract(deductAmount);
                        }
                    }
                    deductAmount = deductAmount.add(thisDeductAmount);
                    // 疗程明细
                    TreatPlanCourseDetails courseDetails = treatPlanCourseDetailsRepository.findOne(id);
                    courseDetails.setDeduct(courseDetails.getDeduct() + thisDeductCount);
                    courseDetails.setExecuteStatus(StateConstants.EXECUTE_STATUS_NO);
                    BusinessUtil.appendRecord(courseDetails);
                    treatPlanCourseDetailsRepository.save(courseDetails);
                    // 保存划扣记录
                    deductRecord.setMemberName(member.getMemberName());
                    deductRecord.setMemberNumber(member.getMemberNumber());
                    deductRecord.setDeductAmount(thisDeductAmount);
                    BusinessUtil.appendRecord(deductRecord);
                    deductRecordRepository.save(deductRecord);
                    // 从疗程账户中减去本次划扣金额
                    courseAccount = courseAccount.subtract(thisDeductAmount);

                    // 记录账户变动后的信息
                    afterAccount(changeDetails, member);
                    changeDetails.setAfterCourseAccount(courseAccount);
                    changeDetails.setRecordId(deductRecord.getId());
                    changeDetails.setRecordType(StateConstants.RECORD_TYPE_DEDUCT);
                    // 保存账户变动
                    accountChangeDetailsRepository.save(changeDetails);
                }
                course.setDeductAmount(deductAmount);
                BusinessUtil.appendRecord(course);
                treatPlanCourseRepository.save(course);
            }
            // 病房划扣处理
            for (Map.Entry<Long, List<DeductRecord>> entry : homeMap.entrySet()) {
                Long homeId = entry.getKey();
                TreatPlanHome home = treatPlanHomeRepository.findOne(homeId);
                // 已划扣金额
                BigDecimal deductAmount = home.getDeductAmount() == null ? BigDecimal.ZERO : home.getDeductAmount();
                List<DeductRecord> list = entry.getValue();
                for (DeductRecord deductRecord : list) {
                    // 账户变动信息
                    AccountChangeDetails changeDetails = new AccountChangeDetails();
                    // 记录充值前账户信息
                    beforeAccount(changeDetails, member);
                    // 记录划扣前疗程金额
                    changeDetails.setBeforeCourseAccount(courseAccount);
                    // 关联业务主键
                    Long id = deductRecord.getBusinessId();
                    // 本次划扣次数
                    int thisDeductCount = deductRecord.getDeductCount();
                    // 本次划扣金额
                    BigDecimal thisDeductAmount = deductRecord.getDeductAmount();
                    // 本次划扣金额
                    BigDecimal temp = deductAmount.add(thisDeductAmount);
                    if (temp.compareTo(home.getTotalPrice()) > 0) {
                        thisDeductAmount = home.getTotalPrice().subtract(deductAmount);
                    }
                    deductAmount = deductAmount.add(thisDeductAmount);
                    if (deductRecord.getTreatType() == StateConstants.TREAT_TYPE_HOME_PROJECT) {
                        TreatPlanHomeProject project = treatPlanHomeProjectRepository.findOne(id);
                        project.setDeduct(project.getDeduct() + thisDeductCount);
                        project.setExecuteStatus(StateConstants.EXECUTE_STATUS_NO);
                        BusinessUtil.appendRecord(project);
                        treatPlanHomeProjectRepository.save(project);
                    } else if (deductRecord.getTreatType() == StateConstants.TREAT_TYPE_HOME_PRODUCT) {
                        TreatPlanHomeProduct product = treatPlanHomeProductRepository.findOne(id);
                        product.setDeduct(product.getDeduct() + thisDeductCount);
                        product.setExecuteStatus(StateConstants.EXECUTE_STATUS_NO);
                        BusinessUtil.appendRecord(product);
                        treatPlanHomeProductRepository.save(product);
                    }
                    // 保存划扣记录
                    deductRecord.setMemberName(member.getMemberName());
                    deductRecord.setMemberNumber(member.getMemberNumber());
                    deductRecord.setDeductAmount(thisDeductAmount);
                    BusinessUtil.appendRecord(deductRecord);
                    deductRecordRepository.save(deductRecord);
                    // 从疗程账户中减去本次划扣金额
                    courseAccount = courseAccount.subtract(thisDeductAmount);

                    // 记录账户变动后的信息
                    afterAccount(changeDetails, member);
                    changeDetails.setAfterCourseAccount(courseAccount);
                    changeDetails.setRecordId(deductRecord.getId());
                    changeDetails.setRecordType(StateConstants.RECORD_TYPE_DEDUCT);
                    // 保存账户变动
                    accountChangeDetailsRepository.save(changeDetails);
                }
                home.setDeductAmount(deductAmount);
                BusinessUtil.appendRecord(home);
                treatPlanHomeRepository.save(home);
            }
            // 更新会员疗程账户信息
            member.setCourseAccount(courseAccount);
            BusinessUtil.appendRecord(member);
            memberRepository.save(member);

            // 划扣收入统计
            Patient p = patientRepository.findOne(member.getPatientId());
            if(p.getDoctorId() != null){
                StringBuilder sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                Query nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                nq.setParameter("id", p.getDoctorId());
                nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                List<StatisticsFinancial> rs = nq.getResultList();
                if(!rs.isEmpty()){
                    sql = new StringBuilder("update statistics_financial set deduct_amount = deduct_amount + :amount where id = :id");
                    nq = em.createNativeQuery(sql.toString());
                    nq.setParameter("amount", totalDeductAmount);
                    nq.setParameter("id", rs.get(0).getId());
                    nq.executeUpdate();
                }else{
                    StatisticsFinancial sf = new StatisticsFinancial();
                    sf.setUserId(p.getDoctorId());
                    sf.setUserName(p.getDoctorName());
                    sf.setDeductAmount(totalDeductAmount);
                    sf.setAccountId(p.getAccountId());
                    sf.setOrganId(p.getOrganId());
                    sf.setOrganName(p.getOrganName());
                    BusinessUtil.appendRecord(sf);
                    statisticsFinancialRepository.save(sf);
                }
            }
            if(p.getNurseId() != null){
                StringBuilder sql = new StringBuilder("select * from statistics_financial where user_id = :id and DATE_FORMAT(creation_time,'%Y-%m-%d') = :time");
                Query nq = em.createNativeQuery(sql.toString(), StatisticsFinancial.class);
                nq.setParameter("id", p.getNurseId());
                nq.setParameter("time", DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
                List<StatisticsFinancial> rs = nq.getResultList();
                if(!rs.isEmpty()){
                    sql = new StringBuilder("update statistics_financial set deduct_amount = deduct_amount + :amount where id = :id");
                    nq = em.createNativeQuery(sql.toString());
                    nq.setParameter("amount", totalDeductAmount);
                    nq.setParameter("id", rs.get(0).getId());
                    nq.executeUpdate();
                }else{
                    StatisticsFinancial sf = new StatisticsFinancial();
                    sf.setUserId(p.getNurseId());
                    sf.setUserName(p.getNurseName());
                    sf.setDeductAmount(totalDeductAmount);
                    sf.setAccountId(p.getAccountId());
                    sf.setOrganId(p.getOrganId());
                    sf.setOrganName(p.getOrganName());
                    BusinessUtil.appendRecord(sf);
                    statisticsFinancialRepository.save(sf);
                }
            }
        }
        // 判断是否打印小票
        int autoPrint = checkPrint();
        Map<String, Object> params = new HashMap();
        if(autoPrint == StateConstants.AUTO_PRINT_YES){
            JSONArray ja = new JSONArray();
            for (DeductRecord record : records) {
                JSONObject jo = new JSONObject();
                jo.put("itemName", record.getItemName());
                jo.put("totalNumber", record.getTotalDeductCount());
                jo.put("useNumber", record.getTickedCount());
                jo.put("deductNumber", record.getDeductCount());
                jo.put("deductAmount", record.getDeductAmount());
                ja.add(jo);
            }
            JSONObject json = new JSONObject();
            json.put("details", ja);
            json.put("medicalNumber", member.getMemberNumber());
            json.put("memberName", member.getMemberName());
            json.put("afterLevelName", member.getLevelName());
            json.put("afterTreatAccount", member.getCourseAccount());
            json.put("deductType", member.getGiftAccount());
            json.put("afterTreatAccount", member.getCourseAccount());
            json.put("creationTime", DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            json.put("createdBy", RequestUtil.getLoginUser().getUsername());
            params.put("task", json);
        }
        params.put("autoPrint", autoPrint);
        result.setParams(params);
        return result;
    }

    @Override
    @Transactional
    public void doAddService(List<ServiceProject> records, Long patientId, Long memberId) {
        List<ChargeDetails> chargeDetails = new ArrayList<>();
        for (ServiceProject record : records) {
            // 治疗方案-服务项目
            TreatPlanServiceProject serviceProject = new TreatPlanServiceProject();
            serviceProject.setPatientId(patientId);
            serviceProject.setMemberId(memberId);
            serviceProject.setProjectId(record.getId());
            serviceProject.setProjectName(record.getName());
            serviceProject.setPrice(record.getPrice());
            BusinessUtil.appendRecord(serviceProject);
            serviceProjectRepository.save(serviceProject);

            ChargeDetails details = new ChargeDetails();
            details.setPatientId(patientId);
            details.setMemberId(memberId);
            details.setBusinessId(serviceProject.getId());
            details.setBusinessType(StateConstants.CHARGE_BUSINESS_TYPE_ONE);
            details.setChargeType(StateConstants.CHARGE_CHARGE_TYPE_SERVICE_PROJECT);
            details.setItemId(record.getId());
            details.setItemName(record.getName());
            details.setQuantity(1);
            details.setPrice(record.getPrice());
            details.setTotalPrice(record.getPrice());
            BusinessUtil.appendRecord(details);
            chargeDetails.add(details);
        }
        // 保存服务项目的待付款记录
        chargeDetailsRepository.save(chargeDetails);
    }

    @Override
    @Transactional
    public Result doMake(List<WaitPayment> records, PayInfo payInfo, PaymentDetails paymentDetails) {
        Result result = new Result();
        result.setCode(CommonConstants.SUCCESS);
        result.setMsg("操作成功");
        // 校验付款金额
        result = validPayAmount(result, payInfo, paymentDetails);
        if (result.getCode().equals(CommonConstants.FAILURE)) {
            return result;
        }
        Member member = memberRepository.findOne(records.get(0).getMemberId());
        if (member != null) {
            // 校验会员账户余额
            result = validMemberAccount(result, member, paymentDetails);
            if (result.getCode().equals(CommonConstants.FAILURE)) {
                return result;
            }
            // 补交
            List<TreatPlanCourse> courseList = new ArrayList<>();
            List<TreatPlanHome> homeList = new ArrayList<>();
            // 会员疗程账户
            BigDecimal courseAccount = member.getCourseAccount();
            for (WaitPayment record : records) {
                // 账户变动信息
                AccountChangeDetails changeDetails = new AccountChangeDetails();
                // 记录充值前账户信息
                beforeAccount(changeDetails, member);
                changeDetails.setBeforeCourseAccount(courseAccount);
                // 已交费
                BigDecimal payAmount = record.getPayAmount();
                // 本次交费
                BigDecimal thisPayAmount = record.getThisPayAmount();
                record.setPayAmount(payAmount.add(thisPayAmount));
                BusinessUtil.appendRecord(record);

                // 生成交费记录
                MakeRecord makeRecord = new MakeRecord();
                makeRecord.setPatientId(member.getPatientId());
                makeRecord.setMemberId(member.getId());
                makeRecord.setMemberName(member.getMemberName());
                makeRecord.setMemberNumber(member.getMemberNumber());
                makeRecord.setRecordId(record.getId());
                makeRecord.setItemName(record.getBusinessName());
                makeRecord.setTotalAmount(record.getTotalAmount());
                makeRecord.setPayAmount(thisPayAmount);
                // 剩余未交费=总费用-已交
                makeRecord.setLastAmount(record.getTotalAmount().subtract(record.getPayAmount()));
                BusinessUtil.appendRecord(makeRecord);
                makeRecordRepository.save(makeRecord);

                // 更新关联业务数据
                StringBuilder sql = new StringBuilder("");
                if (record.getBusinessType() == StateConstants.WAIT_PAYMENT_TREAT_TYPE_COURSE) {
                    sql.append("update treat_plan_course set actual_amount = IFNULL(actual_amount,0) + :actualAmount where id = :id");
                } else if (record.getBusinessType() == StateConstants.WAIT_PAYMENT_TREAT_TYPE_HOME) {
                    sql.append("update treat_plan_home set actual_amount = IFNULL(actual_amount,0) + :actualAmount where id = :id");
                }
                Query query = em.createNativeQuery(sql.toString());
                query.setParameter("actualAmount", thisPayAmount);
                query.setParameter("id", record.getBusinessId());
                query.executeUpdate();

                // 累加到会员疗程账户
                courseAccount = courseAccount.add(thisPayAmount);

                // 记录账户变动后的信息
                afterAccount(changeDetails, member);
                changeDetails.setAfterCourseAccount(courseAccount);
                changeDetails.setRecordId(makeRecord.getId());
                changeDetails.setRecordType(StateConstants.RECORD_TYPE_MAKE);
                // 保存账户变动
                accountChangeDetailsRepository.save(changeDetails);

                PaymentDetails payment = new PaymentDetails();
                payment.setRecordId(makeRecord.getId());
                payment.setRecordType(StateConstants.RECORD_TYPE_MAKE);
                if(paymentDetails.getStore() != null){
                    payment.setStore(record.getThisPayAmount());
                }
                if(paymentDetails.getGift() != null){
                    payment.setGift(record.getThisPayAmount());
                }
                if(paymentDetails.getBankCard() != null){
                    payment.setBankCard(record.getThisPayAmount());
                }
                if(paymentDetails.getAlipay() != null){
                    payment.setAlipay(record.getThisPayAmount());
                }
                if(paymentDetails.getWechat() != null){
                    payment.setWechat(record.getThisPayAmount());
                }
                if(paymentDetails.getCash() != null){
                    payment.setCash(record.getThisPayAmount());
                }
                BusinessUtil.appendRecord(payment);
                paymentDetailsRepository.save(payment);
            }
            // 更新待缴费
            waitPaymentRepository.save(records);
            // 更新会员
            member.setCourseAccount(courseAccount);
            BusinessUtil.appendRecord(member);
            memberRepository.save(member);
        }
        // 判断是否打印小票
        int autoPrint = checkPrint();
        Map<String, Object> params = new HashMap();
        if(autoPrint == StateConstants.AUTO_PRINT_YES){
            JSONObject json = new JSONObject();
            JSONArray ja = new JSONArray();
            for (WaitPayment record : records) {
                JSONObject jo = new JSONObject();
                jo.put("itemName", record.getBusinessName());
                jo.put("totalPrice", record.getTotalAmount());
                jo.put("actualPrice", record.getPayAmount());
                jo.put("quantity", record.getQuantity());
                jo.put("actualPayAmount", record.getThisPayAmount());
                ja.add(jo);
            }
            json.put("details", ja);
            json.put("medicalNumber", member.getMemberNumber());
            json.put("memberName", member.getMemberName());
            json.put("afterLevelName", member.getLevelName());
            json.put("payType", StateConstants.PRINT_PAY_TYPE_MAKE);
            json.put("afterStoreAccount", member.getStoreAccount());
            json.put("afterGiftAccount", member.getGiftAccount());
            json.put("afterTreatAccount", member.getCourseAccount());
            json.put("actualPayAmount", payInfo.getActualAmount());
            json.put("storedAccount", paymentDetails.getStore());
            json.put("giftAccount", paymentDetails.getGift());
            json.put("bankCard", paymentDetails.getBankCard());
            json.put("alipay", paymentDetails.getAlipay());
            json.put("wechat", paymentDetails.getWechat());
            json.put("cash", paymentDetails.getCash());
            json.put("creationTime", DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            json.put("createdBy", RequestUtil.getLoginUser().getUsername());
            params.put("task", json);
        }
        params.put("autoPrint", autoPrint);
        result.setParams(params);
        return result;
    }

    @Override
    @Transactional
    public Result doCreateHistory(Map map) {
        Result result = new Result();
        result.setCode(CommonConstants.SUCCESS);
        result.setMsg("保存成功");
        Long memberId = Long.valueOf(map.get("memberId").toString());
        Member member = memberRepository.findOne(memberId);
        if(member != null){
            String productName = map.get("productName").toString();
            String productCount = map.get("productCount").toString();
            String unitPrice = map.get("unitPrice").toString();
            String totalPrice = map.get("totalPrice").toString();
            AppProductRecord record = new AppProductRecord();
            record.setMemberId(Long.valueOf(memberId));
            record.setProductName(productName);
            record.setProductCount(Integer.parseInt(productCount));
            record.setUnitPrice(new BigDecimal(unitPrice));
            record.setTotalPrice(new BigDecimal(totalPrice));
            record.setAccountId(member.getAccountId());
            record.setUserId(member.getUserId());
            record.setOrganId(member.getOrganId());
            record.setOrganName(member.getOrganName());
            BusinessUtil.appendRecord(record);
            appProductRecordRepository.save(record);
        }
        return result;
    }

    public int checkPrint(){
        int autoPrint = 0;
        SystemConfig systemConfig = systemConfigService.findOne();
        if(systemConfig != null){
            autoPrint = systemConfig.getAutoPrint();
        }
        return autoPrint;
    }

    @Override
    @Transactional
    public void doSave(Member member) {
        if(member.getLevelId() != null){
            MemberLevel level = mongoMemberLevelRepository.findOne(member.getLevelId());
            if(level != null){
                member.setLevelName(level.getLevelName() + (level.getLevel() == null ? "" : level.getLevel()));
            }
        }
        BusinessUtil.appendRecord(member);
        memberRepository.save(member);
    }
}
